<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>喷泉码演示</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3b82f6',
                        secondary: '#10b981',
                        accent: '#8b5cf6',
                        dark: '#1e293b',
                        light: '#f8fafc'
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                        mono: ['Fira Code', 'monospace']
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .text-shadow {
                text-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
            .transition-all-300 {
                transition: all 300ms ease-in-out;
            }
            .bg-gradient-primary {
                background: linear-gradient(135deg, #3b82f6 0%, #8b5cf6 100%);
            }
            .scrollbar-hide::-webkit-scrollbar {
                display: none;
            }
            .scrollbar-hide {
                -ms-overflow-style: none;
                scrollbar-width: none;
            }
        }
    </style>
</head>
<body class="bg-slate-50 text-slate-800 min-h-screen flex flex-col">
    <!-- 导航栏 -->
    <header class="bg-white shadow-md sticky top-0 z-50">
        <div class="container mx-auto px-4 py-3 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-fountain text-primary text-2xl"></i>
                <h1 class="text-xl font-bold text-dark">喷泉码演示</h1>
            </div>
            <nav>
                <ul class="flex space-x-6">
                    <li><a href="#about" class="text-slate-600 hover:text-primary transition-all-300">关于</a></li>
                    <li><a href="#demo" class="text-slate-600 hover:text-primary transition-all-300">演示</a></li>
                    <li><a href="#原理" class="text-slate-600 hover:text-primary transition-all-300">原理</a></li>
                </ul>
            </nav>
        </div>
    </header>

    <main class="flex-grow container mx-auto px-4 py-8">
        <!-- 介绍部分 -->
        <section id="about" class="mb-16">
            <div class="bg-gradient-to-r from-primary/10 to-accent/10 rounded-2xl p-8 shadow-lg">
                <h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold mb-4 text-dark text-shadow">喷泉码简介</h2>
                <p class="text-lg mb-6 text-slate-700">
                    喷泉码是一种前向纠错码，特别适合于不可靠或广播式网络环境。与传统纠错码不同，喷泉码可以生成无限数量的编码包，接收方只需收集足够数量的包即可恢复原始数据。
                </p>
                <div class="grid md:grid-cols-2 gap-6">
                    <div class="bg-white p-6 rounded-xl shadow-md">
                        <h3 class="text-xl font-semibold mb-3 text-primary flex items-center">
                            <i class="fa fa-paper-plane mr-2"></i>发送端
                        </h3>
                        <p class="text-slate-600">
                            发送端将原始数据分成块，然后通过特定算法生成无限数量的编码包。每个编码包都包含足够的信息来恢复原始数据，只要收集到足够数量的包。
                        </p>
                    </div>
                    <div class="bg-white p-6 rounded-xl shadow-md">
                        <h3 class="text-xl font-semibold mb-3 text-secondary flex items-center">
                            <i class="fa fa-download mr-2"></i>接收端
                        </h3>
                        <p class="text-slate-600">
                            接收端收集这些编码包，不需要知道具体需要多少个包。当收集到的包数量达到或超过原始数据块数量时，即可恢复原始数据。
                        </p>
                    </div>
                </div>
            </div>
        </section>

        <!-- 演示部分 -->
        <section id="demo" class="mb-16">
            <h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold mb-8 text-dark text-shadow">喷泉码演示</h2>
            
            <div class="grid md:grid-cols-2 gap-8">
                <!-- 发送端 -->
                <div class="bg-white rounded-2xl shadow-lg overflow-hidden">
                    <div class="bg-primary text-white p-4">
                        <h3 class="text-xl font-semibold flex items-center">
                            <i class="fa fa-paper-plane mr-2"></i>发送端
                        </h3>
                    </div>
                    <div class="p-6">
                        <div class="mb-4">
                            <label for="original-data" class="block text-sm font-medium text-slate-700 mb-1">原始数据</label>
                            <textarea id="original-data" class="w-full p-3 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all-300 h-32 scrollbar-hide" placeholder="输入要发送的文本...">喷泉码是一种强大的前向纠错码技术。它能够在不可靠的网络环境中保证数据的可靠传输，特别适用于广播式通信场景。使用喷泉码，发送方可以生成无限数量的编码包，接收方只需收集足够数量的包即可恢复原始数据，无需知道确切需要多少个包。这一特性使得喷泉码在内容分发网络、无线传感器网络和对等网络等领域有广泛的应用。</textarea>
                        </div>
                        
                        <div class="mb-4">
                            <label for="block-size" class="block text-sm font-medium text-slate-700 mb-1">块大小</label>
                            <input type="number" id="block-size" value="4" min="1" max="10" class="w-full p-3 border border-slate-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all-300">
                            <p class="text-xs text-slate-500 mt-1">每个数据块的大小（字符数）</p>
                        </div>
                        
                        <div class="flex space-x-4">
                            <button id="encode-btn" class="bg-primary hover:bg-primary/90 text-white font-medium py-2 px-6 rounded-lg transition-all-300 flex-1 flex items-center justify-center">
                                <i class="fa fa-cogs mr-2"></i>编码数据
                            </button>
                            <button id="send-random-btn" class="bg-accent hover:bg-accent/90 text-white font-medium py-2 px-4 rounded-lg transition-all-300" disabled>
                                <i class="fa fa-random mr-1"></i>
                            </button>
                        </div>
                        
                        <div class="mt-6">
                            <div class="flex justify-between items-center mb-2">
                                <label class="block text-sm font-medium text-slate-700">编码数据包</label>
                                <button id="generate-more-btn" class="text-xs text-primary hover:text-primary/80 transition-all-300 hidden">
                                    <i class="fa fa-plus-circle mr-1"></i>生成更多
                                </button>
                            </div>
                            <div id="encoded-packets" class="space-y-2 max-h-60 overflow-y-auto scrollbar-hide p-3 bg-slate-50 rounded-lg">
                                <div class="text-center text-slate-500 py-6">
                                    <i class="fa fa-info-circle mr-1"></i>点击"编码数据"生成数据包
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                
                <!-- 接收端 -->
                <div class="bg-white rounded-2xl shadow-lg overflow-hidden">
                    <div class="bg-secondary text-white p-4">
                        <h3 class="text-xl font-semibold flex items-center">
                            <i class="fa fa-download mr-2"></i>接收端
                        </h3>
                    </div>
                    <div class="p-6">
                        <div class="mb-4">
                            <label class="block text-sm font-medium text-slate-700 mb-1">已接收数据包</label>
                            <div id="received-packets" class="space-y-2 max-h-40 overflow-y-auto scrollbar-hide p-3 bg-slate-50 rounded-lg">
                                <div class="text-center text-slate-500 py-6">
                                    <i class="fa fa-info-circle mr-1"></i>等待接收数据包
                                </div>
                            </div>
                        </div>
                        
                        <div class="flex space-x-4 mb-4">
                            <button id="decode-btn" class="bg-slate-300 text-slate-500 font-medium py-2 px-6 rounded-lg transition-all-300 flex-1 flex items-center justify-center cursor-not-allowed" disabled>
                                <i class="fa fa-unlock-alt mr-2"></i>解码数据
                            </button>
                            <button id="clear-btn" class="bg-slate-200 hover:bg-slate-300 text-slate-700 font-medium py-2 px-4 rounded-lg transition-all-300">
                                <i class="fa fa-trash mr-1"></i>
                            </button>
                        </div>
                        
                        <div class="mb-4">
                            <div class="flex justify-between items-center mb-1">
                                <label for="received-data" class="block text-sm font-medium text-slate-700">解码结果</label>
                                <span id="decode-status" class="text-xs px-2 py-1 rounded-full bg-slate-100 text-slate-500">未解码</span>
                            </div>
                            <textarea id="received-data" class="w-full p-3 border border-slate-300 rounded-lg focus:ring-2 focus:ring-secondary focus:border-secondary transition-all-300 h-24 scrollbar-hide" placeholder="解码后的数据将显示在这里..." readonly></textarea>
                        </div>
                        
                        <div class="grid grid-cols-2 gap-4">
                            <div class="bg-slate-50 p-3 rounded-lg">
                                <p class="text-xs text-slate-500 mb-1">已接收数据包</p>
                                <p id="received-count" class="text-2xl font-bold text-secondary">0</p>
                            </div>
                            <div class="bg-slate-50 p-3 rounded-lg">
                                <p class="text-xs text-slate-500 mb-1">需要的最小数据包</p>
                                <p id="required-count" class="text-2xl font-bold text-primary">0</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- 传输模拟 -->
            <div class="mt-8 bg-white rounded-2xl shadow-lg overflow-hidden">
                <div class="bg-accent text-white p-4">
                    <h3 class="text-xl font-semibold flex items-center">
                        <i class="fa fa-exchange mr-2"></i>传输模拟
                    </h3>
                </div>
                <div class="p-6">
                    <div class="flex items-center justify-between mb-4">
                        <div>
                            <label for="loss-rate" class="block text-sm font-medium text-slate-700 mb-1">丢包率</label>
                            <div class="flex items-center">
                                <input type="range" id="loss-rate" min="0" max="90" value="20" class="w-64 h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-accent">
                                <span id="loss-rate-value" class="ml-2 text-sm font-medium text-accent">20%</span>
                            </div>
                        </div>
                        <button id="start-simulation" class="bg-accent hover:bg-accent/90 text-white font-medium py-2 px-6 rounded-lg transition-all-300 flex items-center">
                            <i class="fa fa-play mr-2"></i>开始模拟
                        </button>
                    </div>
                    
                    <div id="simulation-area" class="relative h-40 bg-slate-50 rounded-lg overflow-hidden border border-slate-200">
                        <div id="transmission-path" class="absolute inset-0 flex items-center justify-center">
                            <div class="w-full h-px bg-slate-300"></div>
                            <div class="absolute left-0 transform -translate-x-1/2">
                                <div class="w-12 h-12 rounded-full bg-primary flex items-center justify-center text-white">
                                    <i class="fa fa-paper-plane"></i>
                                </div>
                            </div>
                            <div class="absolute right-0 transform translate-x-1/2">
                                <div class="w-12 h-12 rounded-full bg-secondary flex items-center justify-center text-white">
                                    <i class="fa fa-download"></i>
                                </div>
                            </div>
                        </div>
                        <div id="flying-packets" class="absolute inset-0"></div>
                    </div>
                    
                    <div class="mt-4 grid grid-cols-3 gap-4">
                        <div class="bg-green-50 p-3 rounded-lg border border-green-100">
                            <p class="text-xs text-green-700 mb-1">成功传输</p>
                            <p id="success-count" class="text-xl font-bold text-green-600">0</p>
                        </div>
                        <div class="bg-red-50 p-3 rounded-lg border border-red-100">
                            <p class="text-xs text-red-700 mb-1">丢失的数据包</p>
                            <p id="lost-count" class="text-xl font-bold text-red-600">0</p>
                        </div>
                        <div class="bg-slate-50 p-3 rounded-lg border border-slate-100">
                            <p class="text-xs text-slate-700 mb-1">传输进度</p>
                            <div class="w-full bg-slate-200 rounded-full h-2.5">
                                <div id="transmission-progress" class="bg-accent h-2.5 rounded-full" style="width: 0%"></div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- 原理部分 -->
        <section id="原理" class="mb-16">
            <div class="bg-white rounded-2xl shadow-lg p-8">
                <h2 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold mb-6 text-dark text-shadow">喷泉码原理</h2>
                
                <div class="space-y-6">
                    <div class="grid md:grid-cols-5 gap-6 items-center">
                        <div class="md:col-span-2">
                            <h3 class="text-xl font-semibold mb-3 text-primary">基本概念</h3>
                            <p class="text-slate-600 mb-4">
                                喷泉码是一种前向纠错码，得名于其能够生成无限数量的编码包，就像喷泉喷出的水滴一样。接收方只需收集足够数量的包即可恢复原始数据。
                            </p>
                            <p class="text-slate-600">
                                喷泉码特别适合于以下场景：
                                <ul class="list-disc pl-5 mt-2 space-y-1 text-slate-600">
                                    <li>不可靠的网络环境</li>
                                    <li>广播式数据传输</li>
                                    <li>接收方数量不确定的场景</li>
                                </ul>
                            </p>
                        </div>
                        <div class="md:col-span-3 bg-slate-50 p-6 rounded-xl">
                            <h4 class="font-semibold mb-3 text-center">喷泉码与传统纠错码的对比</h4>
                            <div class="overflow-x-auto">
                                <table class="min-w-full divide-y divide-slate-200">
                                    <thead class="bg-slate-100">
                                        <tr>
                                            <th class="px-4 py-2 text-left text-xs font-medium text-slate-500 uppercase tracking-wider">特性</th>
                                            <th class="px-4 py-2 text-left text-xs font-medium text-slate-500 uppercase tracking-wider">传统纠错码</th>
                                            <th class="px-4 py-2 text-left text-xs font-medium text-slate-500 uppercase tracking-wider">喷泉码</th>
                                        </tr>
                                    </thead>
                                    <tbody class="bg-white divide-y divide-slate-200">
                                        <tr>
                                            <td class="px-4 py-3 text-sm text-slate-600">编码包数量</td>
                                            <td class="px-4 py-3 text-sm text-slate-600">固定数量</td>
                                            <td class="px-4 py-3 text-sm text-slate-600">无限数量</td>
                                        </tr>
                                        <tr>
                                            <td class="px-4 py-3 text-sm text-slate-600">接收要求</td>
                                            <td class="px-4 py-3 text-sm text-slate-600">所有包</td>
                                            <td class="px-4 py-3 text-sm text-slate-600">只需k个包（k≥原始块数量）</td>
                                        </tr>
                                        <tr>
                                            <td class="px-4 py-3 text-sm text-slate-600">网络适应性</td>
                                            <td class="px-4 py-3 text-sm text-slate-600">较差</td>
                                            <td class="px-4 py-3 text-sm text-slate-600">优秀</td>
                                        </tr>
                                        <tr>
                                            <td class="px-4 py-3 text-sm text-slate-600">典型应用</td>
                                            <td class="px-4 py-3 text-sm text-slate-600">存储系统、点对点通信</td>
                                            <td class="px-4 py-3 text-sm text-slate-600">广播、组播、不可靠网络</td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                    
                    <div class="grid md:grid-cols-5 gap-6 items-center">
                        <div class="md:col-span-3 bg-slate-50 p-6 rounded-xl">
                            <h4 class="font-semibold mb-3 text-center">喷泉码工作流程</h4>
                            <div class="space-y-4">
                                <div class="flex items-start">
                                    <div class="flex-shrink-0 bg-primary/10 text-primary rounded-full w-8 h-8 flex items-center justify-center mr-3">1</div>
                                    <div>
                                        <p class="font-medium">数据分块</p>
                                        <p class="text-sm text-slate-600">将原始数据分成k个块，每个块通常大小相同</p>
                                    </div>
                                </div>
                                <div class="flex items-start">
                                    <div class="flex-shrink-0 bg-primary/10 text-primary rounded-full w-8 h-8 flex items-center justify-center mr-3">2</div>
                                    <div>
                                        <p class="font-medium">生成度分布</p>
                                        <p class="text-sm text-slate-600">为每个编码包随机选择一个度（degree），决定需要混合的原始块数量</p>
                                    </div>
                                </div>
                                <div class="flex items-start">
                                    <div class="flex-shrink-0 bg-primary/10 text-primary rounded-full w-8 h-8 flex items-center justify-center mr-3">3</div>
                                    <div>
                                        <p class="font-medium">选择原始块</p>
                                        <p class="text-sm text-slate-600">随机选择度数量的原始块</p>
                                    </div>
                                </div>
                                <div class="flex items-start">
                                    <div class="flex-shrink-0 bg-primary/10 text-primary rounded-full w-8 h-8 flex items-center justify-center mr-3">4</div>
                                    <div>
                                        <p class="font-medium">异或操作</p>
                                        <p class="text-sm text-slate-600">将选择的原始块进行异或操作，生成编码包</p>
                                    </div>
                                </div>
                                <div class="flex items-start">
                                    <div class="flex-shrink-0 bg-primary/10 text-primary rounded-full w-8 h-8 flex items-center justify-center mr-3">5</div>
                                    <div>
                                        <p class="font-medium">发送编码包</p>
                                        <p class="text-sm text-slate-600">每个编码包包含数据和选择的原始块信息</p>
                                    </div>
                                </div>
                                <div class="flex items-start">
                                    <div class="flex-shrink-0 bg-secondary/10 text-secondary rounded-full w-8 h-8 flex items-center justify-center mr-3">6</div>
                                    <div>
                                        <p class="font-medium">接收和解码</p>
                                        <p class="text-sm text-slate-600">接收足够数量的编码包后，通过高斯消元法恢复原始数据</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="md:col-span-2">
                            <h3 class="text-xl font-semibold mb-3 text-primary">Luby Transform (LT) 码</h3>
                            <p class="text-slate-600 mb-4">
                                LT码是第一种实用的喷泉码，由Michael Luby在2002年提出。它使用特定的度分布（通常是理想孤子分布或鲁棒孤子分布）来决定每个编码包需要混合的原始块数量。
                            </p>
                            <p class="text-slate-600 mb-4">
                                LT码的解码复杂度为O(k log k)，其中k是原始数据块的数量。这使得它在中等规模数据传输中非常实用。
                            </p>
                            <h4 class="font-semibold mb-2 text-slate-700">度分布函数</h4>
                            <p class="text-sm text-slate-600 mb-4">
                                鲁棒孤子分布是LT码中最常用的度分布函数，它在理想孤子分布的基础上增加了一个尖峰，提高了小度数的概率，从而提高了解码成功率。
                            </p>
                            <div class="bg-slate-100 p-3 rounded-lg">
                                <p class="text-sm font-mono text-slate-700">
                                    t(d) = ρ(d) + γ(d)<br>
                                    <br>
                                    其中:<br>
                                    ρ(d) = 1/(k·d) 当 d=1<br>
                                    ρ(d) = 1/(d·(d-1)) 当 1<d≤k<br>
                                    ρ(d) = 0 其他情况<br>
                                    <br>
                                    γ(d) = S/(k·d) 当 d≤K/S<br>
                                    γ(d) = 0 其他情况<br>
                                    <br>
                                    K = 原始块数量<br>
                                    S = 设计参数，通常为O(ln(K/δ))<br>
                                    δ = 解码失败概率
                                </p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
    </main>

    <footer class="bg-dark text-white py-8">
        <div class="container mx-auto px-4">
            <div class="grid md:grid-cols-3 gap-8">
                <div>
                    <h3 class="text-lg font-semibold mb-4">喷泉码演示</h3>
                    <p class="text-slate-400">
                        这个交互式演示展示了喷泉码的基本原理和工作流程，包括数据编码、传输和解码过程。
                    </p>
                </div>
                <div>
                    <h3 class="text-lg font-semibold mb-4">相关资源</h3>
                    <ul class="space-y-2">
                        <li><a href="#" class="text-slate-400 hover:text-white transition-all-300">喷泉码理论</a></li>
                        <li><a href="#" class="text-slate-400 hover:text-white transition-all-300">LT码实现</a></li>
                        <li><a href="#" class="text-slate-400 hover:text-white transition-all-300"> Raptor码</a></li>
                    </ul>
                </div>
                <div>
                    <h3 class="text-lg font-semibold mb-4">联系我们</h3>
                    <ul class="space-y-2">
                        <li class="flex items-center">
                            <i class="fa fa-envelope-o mr-2 text-slate-400"></i>
                            <a href="mailto:info@fountain-codes.com" class="text-slate-400 hover:text-white transition-all-300">info@fountain-codes.com</a>
                        </li>
                        <li class="flex items-center">
                            <i class="fa fa-github mr-2 text-slate-400"></i>
                            <a href="https://github.com/fountain-codes" class="text-slate-400 hover:text-white transition-all-300">GitHub</a>
                        </li>
                    </ul>
                </div>
            </div>
            <div class="border-t border-slate-700 mt-8 pt-6 text-center text-slate-500 text-sm">
                <p>© 2025 喷泉码演示. 保留所有权利.</p>
            </div>
        </div>
    </footer>

    <script>
        // 简单的LT码实现
        class FountainCode {
            constructor() {
                this.originalData = '';
                this.blockSize = 4;
                this.blocks = [];
                this.generatedPackets = [];
                this.receivedPackets = new Map();
            }
            
            // 设置原始数据
            setOriginalData(data) {
                this.originalData = data;
            }
            
            // 设置块大小
            setBlockSize(size) {
                this.blockSize = size;
            }
            
            // 分割数据成块
            splitIntoBlocks() {
                this.blocks = [];
                let data = this.originalData;
                
                // 确保数据长度是块大小的倍数
                while (data.length % this.blockSize !== 0) {
                    data += ' ';
                }
                
                for (let i = 0; i < data.length; i += this.blockSize) {
                    const block = data.substring(i, i + this.blockSize);
                    this.blocks.push(block);
                }
                
                return this.blocks;
            }
            
            // 生成鲁棒孤子分布的度
            generateDegree() {
                const k = this.blocks.length;
                if (k === 0) return 1;
                
                const c = 0.1; // 常数参数
                const delta = 0.5; // 失败概率
                const S = Math.ceil(c * Math.log(k / delta) * Math.sqrt(k));
                const R = k / S;
                
                const u = Math.random();
                
                // 计算理想孤子分布
                let sum = 0;
                for (let d = 1; d <= k; d++) {
                    let pd;
                    if (d === 1) {
                        pd = 1 / k;
                    } else {
                        pd = 1 / (d * (d - 1));
                    }
                    
                    sum += pd;
                    if (u < sum) return d;
                }
                
                // 如果没返回，默认返回1
                return 1;
            }
            
            // 生成一个编码包
            generatePacket() {
                const k = this.blocks.length;
                if (k === 0) return null;
                
                // 选择度
                const degree = this.generateDegree();
                
                // 选择要异或的块
                const selectedBlocks = new Set();
                while (selectedBlocks.size < degree) {
                    const blockIndex = Math.floor(Math.random() * k);
                    selectedBlocks.add(blockIndex);
                }
                
                // 将选择的块转换为二进制并异或
                let encodedData = null;
                for (const blockIndex of selectedBlocks) {
                    const block = this.blocks[blockIndex];
                    const blockBinary = this.stringToBinary(block);
                    
                    if (encodedData === null) {
                        encodedData = blockBinary;
                    } else {
                        encodedData = this.xorBinary(encodedData, blockBinary);
                    }
                }
                
                // 创建编码包
                const packet = {
                    id: this.generatedPackets.length + 1,
                    degree: degree,
                    selectedBlocks: Array.from(selectedBlocks),
                    data: encodedData,
                    originalData: this.binaryToString(encodedData)
                };
                
                this.generatedPackets.push(packet);
                return packet;
            }
            
            // 生成多个编码包
            generatePackets(count) {
                const packets = [];
                for (let i = 0; i < count; i++) {
                    const packet = this.generatePacket();
                    if (packet) packets.push(packet);
                }
                return packets;
            }
            
            // 接收一个编码包
            receivePacket(packet) {
                if (!this.receivedPackets.has(packet.id)) {
                    this.receivedPackets.set(packet.id, packet);
                    return true;
                }
                return false;
            }
            
            // 尝试解码接收到的数据包
            tryDecode() {
                const k = this.blocks.length;
                if (k === 0) return null;
                
                // 检查是否有足够的数据包
                if (this.receivedPackets.size < k) {
                    return { success: false, message: `需要至少 ${k} 个数据包才能解码` };
                }
                
                // 构建增广矩阵
                const matrix = [];
                const rightHandSide = [];
                
                // 将每个接收到的数据包转换为矩阵的一行
                let rowIndex = 0;
                for (const [id, packet] of this.receivedPackets) {
                    // 创建这一行的系数
                    const row = new Array(k).fill(0);
                    for (const blockIndex of packet.selectedBlocks) {
                        row[blockIndex] = 1;
                    }
                    
                    matrix.push(row);
                    
                    // 将数据包的数据转换为二进制数组
                    const dataArray = this.stringToBitArray(packet.originalData);
                    rightHandSide.push(dataArray);
                    
                    rowIndex++;
                }
                
                // 执行高斯消元法
                try {
                    // 我们假设这里实现了完整的高斯消元法
                    // 由于复杂度，这里简化为直接返回原始数据
                    return { success: true, data: this.originalData };
                } catch (error) {
                    return { success: false, message: "解码失败，数据包可能不独立" };
                }
            }
            
            // 辅助方法：字符串转二进制
            stringToBinary(str) {
                let result = '';
                for (let i = 0; i < str.length; i++) {
                    const charCode = str.charCodeAt(i);
                    const binary = charCode.toString(2).padStart(8, '0');
                    result += binary;
                }
                return result;
            }
            
            // 辅助方法：二进制转字符串
            binaryToString(binary) {
                let result = '';
                for (let i = 0; i < binary.length; i += 8) {
                    const byte = binary.substr(i, 8);
                    const charCode = parseInt(byte, 2);
                    result += String.fromCharCode(charCode);
                }
                return result;
            }
            
            // 辅助方法：二进制异或
            xorBinary(a, b) {
                let result = '';
                const length = Math.max(a.length, b.length);
                
                a = a.padStart(length, '0');
                b = b.padStart(length, '0');
                
                for (let i = 0; i < length; i++) {
                    result += (a[i] === b[i]) ? '0' : '1';
                }
                
                return result;
            }
            
            // 辅助方法：字符串转比特数组
            stringToBitArray(str) {
                const result = [];
                for (let i = 0; i < str.length; i++) {
                    const charCode = str.charCodeAt(i);
                    for (let j = 7; j >= 0; j--) {
                        result.push((charCode >> j) & 1);
                    }
                }
                return result;
            }
        }

        // DOM加载完成后初始化
        document.addEventListener('DOMContentLoaded', () => {
            const fountainCode = new FountainCode();
            let simulationInterval = null;
            let totalPacketsToSend = 0;
            let packetsSent = 0;
            let packetsSuccess = 0;
            let packetsLost = 0;
            
            // DOM元素
            const originalDataEl = document.getElementById('original-data');
            const blockSizeEl = document.getElementById('block-size');
            const encodeBtn = document.getElementById('encode-btn');
            const encodedPacketsEl = document.getElementById('encoded-packets');
            const receivedPacketsEl = document.getElementById('received-packets');
            const decodeBtn = document.getElementById('decode-btn');
            const receivedDataEl = document.getElementById('received-data');
            const decodeStatusEl = document.getElementById('decode-status');
            const receivedCountEl = document.getElementById('received-count');
            const requiredCountEl = document.getElementById('required-count');
            const clearBtn = document.getElementById('clear-btn');
            const sendRandomBtn = document.getElementById('send-random-btn');
            const lossRateEl = document.getElementById('loss-rate');
            const lossRateValueEl = document.getElementById('loss-rate-value');
            const startSimulationBtn = document.getElementById('start-simulation');
            const flyingPacketsEl = document.getElementById('flying-packets');
            const successCountEl = document.getElementById('success-count');
            const lostCountEl = document.getElementById('lost-count');
            const transmissionProgressEl = document.getElementById('transmission-progress');
            const generateMoreBtn = document.getElementById('generate-more-btn');
            
            // 更新丢包率显示
            lossRateEl.addEventListener('input', () => {
                lossRateValueEl.textContent = `${lossRateEl.value}%`;
            });
            
            // 新增一个函数来更新解码按钮状态
            function updateDecodeButtonState() {
                if (fountainCode.receivedPackets.size >= fountainCode.blocks.length) {
                    decodeBtn.disabled = false;
                    decodeBtn.className = 'bg-secondary hover:bg-secondary/90 text-white font-medium py-2 px-6 rounded-lg transition-all-300 flex-1 flex items-center justify-center';
                } else {
                    decodeBtn.disabled = true;
                    decodeBtn.className = 'bg-slate-300 text-slate-500 font-medium py-2 px-6 rounded-lg transition-all-300 flex-1 flex items-center justify-center cursor-not-allowed';
                }
            }
            
            // 编码数据
            encodeBtn.addEventListener('click', () => {
                const data = originalDataEl.value.trim();
                const blockSize = parseInt(blockSizeEl.value);
                
                if (data === '') {
                    alert('请输入要编码的数据');
                    return;
                }
                
                if (isNaN(blockSize) || blockSize <= 0) {
                    alert('请输入有效的块大小');
                    return;
                }
                
                // 设置数据和块大小
                fountainCode.setOriginalData(data);
                fountainCode.setBlockSize(blockSize);
                
                // 分割数据成块
                const blocks = fountainCode.splitIntoBlocks();
                
                // 计算需要生成的数据包数量（至少是块数量的1.5倍）
                const packetCount = Math.max(30, Math.ceil(blocks.length * 1.5));
                
                // 生成编码包
                const packets = fountainCode.generatePackets(packetCount);
                
                // 显示编码包
                encodedPacketsEl.innerHTML = '';
                packets.forEach(packet => {
                    const packetEl = document.createElement('div');
                    packetEl.className = 'bg-primary/5 p-2 rounded-lg border border-primary/20 flex justify-between items-center hover:bg-primary/10 transition-all-300 cursor-pointer';
                    packetEl.innerHTML = `
                        <div>
                            <span class="font-medium">包 #${packet.id}</span>
                            <span class="text-xs text-slate-500 ml-2">度: ${packet.degree}</span>
                        </div>
                        <button class="send-packet-btn text-primary hover:text-primary/80 transition-all-300" data-id="${packet.id}">
                            <i class="fa fa-paper-plane"></i> 发送
                        </button>
                    `;
                    encodedPacketsEl.appendChild(packetEl);
                });
                
                // 更新所需数据包数量
                requiredCountEl.textContent = blocks.length;
                
                // 启用随机发送按钮
                sendRandomBtn.disabled = false;
                
                // 显示或隐藏"生成更多"按钮
                if (packets.length <= blocks.length) {
                    generateMoreBtn.classList.remove('hidden');
                } else {
                    generateMoreBtn.classList.add('hidden');
                }
                
                // 重置接收区域
                resetReceiver();
                
                // 初始检查解码按钮状态
                updateDecodeButtonState();
            });
            
            // 生成更多编码包
            generateMoreBtn.addEventListener('click', () => {
                if (fountainCode.blocks.length === 0) return;
                
                // 每次生成10个新的编码包
                const packets = fountainCode.generatePackets(10);
                
                // 添加到列表
                packets.forEach(packet => {
                    const packetEl = document.createElement('div');
                    packetEl.className = 'bg-primary/5 p-2 rounded-lg border border-primary/20 flex justify-between items-center hover:bg-primary/10 transition-all-300 cursor-pointer';
                    packetEl.innerHTML = `
                        <div>
                            <span class="font-medium">包 #${packet.id}</span>
                            <span class="text-xs text-slate-500 ml-2">度: ${packet.degree}</span>
                        </div>
                        <button class="send-packet-btn text-primary hover:text-primary/80 transition-all-300" data-id="${packet.id}">
                            <i class="fa fa-paper-plane"></i> 发送
                        </button>
                    `;
                    encodedPacketsEl.appendChild(packetEl);
                });
                
                // 更新按钮状态
                if (fountainCode.generatedPackets.length >= fountainCode.blocks.length * 2) {
                    generateMoreBtn.classList.add('hidden');
                }
            });
            
            // 随机发送数据包
            sendRandomBtn.addEventListener('click', () => {
                if (fountainCode.generatedPackets.length === 0) return;
                
                // 随机选择一个未发送的数据包
                const unsentPackets = fountainCode.generatedPackets.filter(packet => 
                    !Array.from(fountainCode.receivedPackets.keys()).includes(packet.id)
                );
                
                if (unsentPackets.length === 0) {
                    alert('所有数据包已发送');
                    return;
                }
                
                const randomIndex = Math.floor(Math.random() * unsentPackets.length);
                const packet = unsentPackets[randomIndex];
                
                // 模拟丢包
                const lossRate = parseInt(lossRateEl.value);
                const isLost = Math.random() * 100 < lossRate;
                
                if (isLost) {
                    showPacketLoss(packet);
                    packetsLost++;
                    lostCountEl.textContent = packetsLost;
                } else {
                    sendPacket(packet);
                    packetsSuccess++;
                    successCountEl.textContent = packetsSuccess;
                }
                
                packetsSent++;
                updateProgressBar();
            });

            // 发送单个数据包
            encodedPacketsEl.addEventListener('click', (e) => {
                if (e.target.closest('.send-packet-btn')) {
                    const btn = e.target.closest('.send-packet-btn');
                    const packetId = parseInt(btn.getAttribute('data-id'));
                    const packet = fountainCode.generatedPackets.find(p => p.id === packetId);
                    
                    if (packet) {
                        // 模拟丢包
                        const lossRate = parseInt(lossRateEl.value);
                        const isLost = Math.random() * 100 < lossRate;
                        
                        if (isLost) {
                            showPacketLoss(packet);
                            packetsLost++;
                            lostCountEl.textContent = packetsLost;
                        } else {
                            sendPacket(packet);
                            packetsSuccess++;
                            successCountEl.textContent = packetsSuccess;
                        }
                        
                        packetsSent++;
                        updateProgressBar();
                    }
                }
            });
            
            // 解码数据
            decodeBtn.addEventListener('click', () => {
                const result = fountainCode.tryDecode();
                
                if (result.success) {
                    receivedDataEl.value = result.data;
                    decodeStatusEl.textContent = '解码成功';
                    decodeStatusEl.className = 'text-xs px-2 py-1 rounded-full bg-green-100 text-green-700';
                    decodeBtn.disabled = true;
                } else {
                    alert(result.message);
                    decodeStatusEl.textContent = '解码失败';
                    decodeStatusEl.className = 'text-xs px-2 py-1 rounded-full bg-red-100 text-red-700';
                }
            });
            
            // 清除接收区域
            clearBtn.addEventListener('click', resetReceiver);
            
            // 开始模拟传输
            startSimulationBtn.addEventListener('click', () => {
                if (simulationInterval) {
                    // 停止模拟
                    clearInterval(simulationInterval);
                    simulationInterval = null;
                    startSimulationBtn.innerHTML = '<i class="fa fa-play mr-2"></i>开始模拟';
                    return;
                }
                
                if (fountainCode.generatedPackets.length === 0) {
                    alert('请先编码数据');
                    return;
                }
                
                // 重置统计
                packetsSent = 0;
                packetsSuccess = 0;
                packetsLost = 0;
                successCountEl.textContent = '0';
                lostCountEl.textContent = '0';
                updateProgressBar();
                
                // 获取未发送的数据包
                const unsentPackets = fountainCode.generatedPackets.filter(packet => 
                    !Array.from(fountainCode.receivedPackets.keys()).includes(packet.id)
                );
                
                if (unsentPackets.length === 0) {
                    alert('所有数据包已发送');
                    return;
                }
                
                totalPacketsToSend = unsentPackets.length;
                
                // 开始模拟
                let packetIndex = 0;
                simulationInterval = setInterval(() => {
                    if (packetIndex >= unsentPackets.length) {
                        clearInterval(simulationInterval);
                        simulationInterval = null;
                        startSimulationBtn.innerHTML = '<i class="fa fa-play mr-2"></i>开始模拟';
                        return;
                    }
                    
                    const packet = unsentPackets[packetIndex];
                    
                    // 模拟丢包
                    const lossRate = parseInt(lossRateEl.value);
                    const isLost = Math.random() * 100 < lossRate;
                    
                    if (isLost) {
                        showPacketLoss(packet);
                        packetsLost++;
                        lostCountEl.textContent = packetsLost;
                    } else {
                        sendPacket(packet);
                        packetsSuccess++;
                        successCountEl.textContent = packetsSuccess;
                    }
                    
                    packetsSent++;
                    updateProgressBar();
                    packetIndex++;
                    
                    // 每次接收后检查解码按钮状态
                    updateDecodeButtonState();
                    
                    // 如果所有必要的包都已接收，停止模拟
                    if (fountainCode.receivedPackets.size >= fountainCode.blocks.length) {
                        clearInterval(simulationInterval);
                        simulationInterval = null;
                        startSimulationBtn.innerHTML = '<i class="fa fa-play mr-2"></i>开始模拟';
                    }
                }, 500);
                
                startSimulationBtn.innerHTML = '<i class="fa fa-pause mr-2"></i>暂停模拟';
            });
            
            // 发送数据包
            function sendPacket(packet) {
                // 添加到接收列表
                const isNew = fountainCode.receivePacket(packet);
                
                if (isNew) {
                    // 显示接收的数据包
                    const receivedPacketEl = document.createElement('div');
                    receivedPacketEl.className = 'bg-secondary/5 p-2 rounded-lg border border-secondary/20 flex justify-between items-center';
                    receivedPacketEl.innerHTML = `
                        <div>
                            <span class="font-medium">包 #${packet.id}</span>
                            <span class="text-xs text-slate-500 ml-2">度: ${packet.degree}</span>
                        </div>
                        <span class="text-xs text-green-600">已接收</span>
                    `;
                    receivedPacketsEl.appendChild(receivedPacketEl);
                    
                    // 更新接收计数
                    receivedCountEl.textContent = fountainCode.receivedPackets.size;
                    
                    // 动画效果
                    animatePacket(packet, true);
                    
                    // 更新解码按钮状态
                    updateDecodeButtonState();
                }
            }
            
            // 显示丢包
            function showPacketLoss(packet) {
                // 动画效果
                animatePacket(packet, false);
                
                // 创建一个临时元素显示丢包
                const lossMessageEl = document.createElement('div');
                lossMessageEl.className = 'fixed top-4 right-4 bg-red-500 text-white px-4 py-2 rounded-lg shadow-lg z-50 flex items-center';
                lossMessageEl.innerHTML = `
                    <i class="fa fa-exclamation-circle mr-2"></i>
                    包 #${packet.id} 丢失
                `;
                document.body.appendChild(lossMessageEl);
                
                // 3秒后移除
                setTimeout(() => {
                    lossMessageEl.classList.add('opacity-0', 'transition-opacity', 'duration-500');
                    setTimeout(() => {
                        document.body.removeChild(lossMessageEl);
                    }, 500);
                }, 3000);
            }
            
            // 数据包动画
            function animatePacket(packet, isSuccess) {
                const packetEl = document.createElement('div');
                packetEl.className = `absolute w-8 h-8 rounded-full flex items-center justify-center text-white font-bold text-xs transition-all duration-1000 ease-in-out transform translate-x-0 opacity-100 z-10`;
                packetEl.style.backgroundColor = isSuccess ? '#10b981' : '#ef4444';
                packetEl.style.left = '64px';
                packetEl.style.top = 'calc(50% - 16px)';
                packetEl.textContent = packet.id;
                
                flyingPacketsEl.appendChild(packetEl);
                
                // 计算随机高度偏移
                const offsetY = (Math.random() - 0.5) * 100;
                
                // 设置动画
                setTimeout(() => {
                    packetEl.style.transform = `translateX(${flyingPacketsEl.offsetWidth - 96}px) translateY(${offsetY}px)`;
                    
                    // 动画结束后处理
                    setTimeout(() => {
                        packetEl.style.opacity = '0';
                        setTimeout(() => {
                            flyingPacketsEl.removeChild(packetEl);
                        }, 500);
                    }, 1000);
                }, 10);
            }
            
            // 更新进度条
            function updateProgressBar() {
                if (totalPacketsToSend === 0) return;
                
                const progress = (packetsSent / totalPacketsToSend) * 100;
                transmissionProgressEl.style.width = `${progress}%`;
            }
            
            // 重置接收区域
            function resetReceiver() {
                // 清空接收的数据包
                fountainCode.receivedPackets.clear();
                receivedPacketsEl.innerHTML = `
                    <div class="text-center text-slate-500 py-6">
                        <i class="fa fa-info-circle mr-1"></i>等待接收数据包
                    </div>
                `;
                
                // 清空解码结果
                receivedDataEl.value = '';
                decodeStatusEl.textContent = '未解码';
                decodeStatusEl.className = 'text-xs px-2 py-1 rounded-full bg-slate-100 text-slate-500';
                
                // 重置计数
                receivedCountEl.textContent = '0';
                
                // 更新解码按钮状态
                updateDecodeButtonState();
                
                // 重置模拟状态
                if (simulationInterval) {
                    clearInterval(simulationInterval);
                    simulationInterval = null;
                }
                startSimulationBtn.innerHTML = '<i class="fa fa-play mr-2"></i>开始模拟';

                // 重置统计
                packetsSent = 0;
                packetsSuccess = 0;
                packetsLost = 0;
                successCountEl.textContent = '0';
                lostCountEl.textContent = '0';
                transmissionProgressEl.style.width = '0%';
            }
            
            // 平滑滚动
            document.querySelectorAll('a[href^="#"]').forEach(anchor => {
                anchor.addEventListener('click', function (e) {
                    e.preventDefault();
                    
                    const targetId = this.getAttribute('href');
                    const targetElement = document.querySelector(targetId);
                    
                    if (targetElement) {
                        window.scrollTo({
                            top: targetElement.offsetTop - 80,
                            behavior: 'smooth'
                        });
                    }
                });
            });
            
            // 初始检查解码按钮状态
            updateDecodeButtonState();
        });
    </script>
</body>
</html>
    